# app/main.py
import asyncio
from fastapi import FastAPI, WebSocket, Request
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.util import queue
from starlette.responses import JSONResponse

from app.core.config import settings
from app.core.state import app_state
from app.core.database import initialize_device_data, SessionLocal, \
    initialize_admin_user, initialize_database_tables
from app.utils.device_cache import device_cache
from app.utils.device_manager import check_device_online_status
from app.utils.ws_manager import frontend_manager
from app.core.logger import get_logger
from app.models.models import Device
from app.api.routers import auth
import gc

logger = get_logger(__name__)

# 创建主应用（端口8888）
main_app = FastAPI()
main_app.include_router(auth.router, prefix="/api", tags=["auth"])

# 配置CORS
main_app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 创建设备控制应用（端口8887）
control_app = FastAPI()

# 在应用启动时初始化
@main_app.on_event("startup")
async def startup_event():
    from app.core.database import Base, engine
    from app.utils.update_queue import update_queue
    Base.metadata.create_all(bind=engine)

    # 配置垃圾回收
    gc.set_threshold(500, 15, 5)  # 调整GC阈值
    gc.enable()  # 确保GC启用

    # 初始化数据库表
    initialize_database_tables()
    # 初始化设备数据
    initialize_device_data()
    # 初始化管理员用户
    initialize_admin_user()
    # 定时刷新缓存
    asyncio.create_task(refresh_cache_periodically())
    # 初始化缓存
    await device_cache.init()
    # 清理现有缓存，确保重新从数据库加载
    await device_cache.clear_cache()
    # 从数据库加载设备数据到缓存
    await load_devices_from_db_to_cache()
    # 启动数据库工作线程
    app_state.start_db_worker()
    # 创建安全的数据库操作函数
    app_state.safe_db_operation = app_state.create_safe_db_operation()
    # 初始化 Redis 连接
    await device_cache.init()
    # 启动批量更新任务
    asyncio.create_task(update_queue.process_batch())
    # 启动设备状态检查任务
    asyncio.create_task(check_devices_status())

async def load_devices_from_db_to_cache():
    """从数据库加载设备数据到缓存"""
    await device_cache.clear_cache()
    try:
        from app.core.database import get_all_devices
        devices = await get_all_devices()
        if devices:
            logger.info(f"从数据库加载 {len(devices)} 台设备到缓存")
            await device_cache.batch_update(devices)
        else:
            logger.warning("数据库中没有设备数据")
    except Exception as e:
        logger.error(f"从数据库加载设备到缓存失败: {e}")


async def refresh_cache_periodically():
    """定期刷新缓存"""
    while True:
        try:
            logger.info("开始刷新设备缓存")
            # 从数据库加载所有设备
            db = SessionLocal()
            try:
                devices = db.query(Device).all()
                device_dicts = [device.to_dict() for device in devices]

                # 批量更新缓存
                await device_cache.batch_update(device_dicts)
                logger.info(f"成功刷新 {len(device_dicts)} 台设备缓存")
            finally:
                db.close()
        except Exception as e:
            logger.error(f"刷新缓存失败: {e}")

        await asyncio.sleep(settings.REFRESH_CACHE_PERIODICALLY_INTERVAL)

# 在应用关闭时清理
@main_app.on_event("shutdown")
async def shutdown_event():
    # 停止数据库工作线程
    app_state.stop_db_worker()


# 后台任务：检查设备在线状态
async def check_devices_status():
    """定期检查设备在线状态"""
    while True:
        updated_devices = await check_device_online_status()
        if updated_devices:
            # 通知前端有设备状态更新
            for dev_id in updated_devices:
                device = await device_cache.get_device(dev_id)
                if device:
                    # 确保状态是离线
                    device["online_status"] = "offline"
                    # await frontend_manager.broadcast({
                    #     "type": "device_update",
                    #     "data": device
                    # })
        await asyncio.sleep(settings.DEVICE_STATUS_CHECK_INTERVAL)


# 设备WebSocket连接 - 在控制应用上
@main_app.websocket("/ws")
async def device_websocket(websocket: WebSocket):
    from app.utils.device_manager import handle_device_websocket
    await handle_device_websocket(websocket, app_state.safe_db_operation)


# 设备信息WebSocket连接 - 在控制应用上
@control_app.websocket("/ws/manager")
async def device_info_websocket(websocket: WebSocket):
    from app.utils.device_info_manager import handle_device_info_websocket
    await handle_device_info_websocket(websocket)


# 从数据库中获取全部设备 - 在主应用上
@control_app.get("/devices")
async def get_devices():
    from app.core.database import get_all_devices_db
    # 数据库获取全部设备，而非缓存
    devices = await get_all_devices_db()
    return devices

@control_app.options("/devices")
async def get_devices():
    from app.core.database import get_all_devices_db
    # 数据库获取全部设备，而非缓存
    devices = await get_all_devices_db()
    return devices

# 设备注册接口 - 在主应用上
@main_app.post("/device/factory_activated")
async def device_factory_activated(device_data: dict, request: Request):
    from app.utils.device_manager import factory_activate_device
    return await factory_activate_device(device_data, request)

# 设备删除接口 - 在主应用上
@control_app.post("/devices/delete")
async def delete_device_endpoint(device_data: dict, request: Request):
    """
    删除设备接口
    请求参数示例: {"dev_id": "设备ID"}
    """
    dev_id = device_data.get("dev_id")
    if not dev_id:
        return JSONResponse(
            content={},
            status_code=400
        )

    from app.utils.device_manager import delete_device
    result = await delete_device(dev_id, request)

    if "error" in result:
        return JSONResponse(
            status_code=400,
            content={"error": result["error"]}
        )

    return result


# 设备注册日志API - 在主应用上
@control_app.get("/admin/registration-logs")
async def get_registration_logs(
    start_date: str = None,
    end_date: str = None,
    success: bool = None,
    dev_id: str = None
):
    """查询设备注册日志 - 一次性返回所有结果"""
    from datetime import datetime, timedelta
    from app.core.database import get_db_context
    from app.models.models import DeviceRegistrationLog

    try:
        # 使用异步上下文管理器获取数据库会话
        async with get_db_context() as db:
            query = db.query(DeviceRegistrationLog)

            # 应用筛选条件
            if start_date:
                start_date = datetime.strptime(start_date, "%Y-%m-%d")
                query = query.filter(DeviceRegistrationLog.registration_time >= start_date)
            if end_date:
                end_date = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
                query = query.filter(DeviceRegistrationLog.registration_time < end_date)
            if success is not None:
                query = query.filter(DeviceRegistrationLog.success == success)
            if dev_id:
                query = query.filter(DeviceRegistrationLog.dev_id == dev_id)

            # 排序
            query = query.order_by(DeviceRegistrationLog.registration_time.desc())

            # 获取所有日志
            logs = query.all()

            return {
                "total": len(logs),
                "data": [
                    {
                        "id": log.id,
                        "registration_time": log.registration_time,
                        "success": log.success,
                        "dev_id": log.dev_id,
                        "ip_address": log.ip_address,
                        "error_message": log.error_message
                    }
                    for log in logs
                ]
            }
    except Exception as e:
        logger.error(f"查询注册日志失败: {str(e)}")
        return {
            "error": "查询注册日志失败",
            "details": str(e)
        }

@main_app.get("/admin/registration-log/{log_id}")
async def get_registration_log_detail(log_id: int):
    """获取注册日志详情"""
    from app.core.database import get_db_context
    from app.models.models import DeviceRegistrationLog

    try:
        # 使用异步上下文管理器获取数据库会话
        async with get_db_context() as db:
            log = db.query(DeviceRegistrationLog).filter(DeviceRegistrationLog.id == log_id).first()
            if not log:
                return {
                    "error": "日志未找到"
                }

            return {
                "id": log.id,
                "registration_time": log.registration_time,
                "success": log.success,
                "request_data": log.request_data,
                "response_data": log.response_data,
                "error_message": log.error_message,
                "dev_id": log.dev_id,
                "ip_address": log.ip_address,
                "user_agent": log.user_agent
            }
    except Exception as e:
        logger.error(f"获取日志详情失败: {str(e)}")
        return {
            "error": "获取日志详情失败",
            "details": str(e)
        }


if __name__ == "__main__":
    import uvicorn
    import asyncio
    import signal

    # 创建服务器配置
    config_main = uvicorn.Config(
        "app.main:main_app",
        host="0.0.0.0",
        port=8888,
        reload=False,
        workers=1,
        limit_concurrency=1000,
        timeout_keep_alive=60,
        backlog=2048
    )

    config_control = uvicorn.Config(
        "app.main:control_app",
        host="0.0.0.0",
        port=8887,
        reload=False,
        workers=1,
        limit_concurrency=1000,
        timeout_keep_alive=60,
        backlog=2048
    )

    # 创建服务器实例
    server_main = uvicorn.Server(config_main)
    server_control = uvicorn.Server(config_control)


    # 启动服务器
    async def run_servers():
        # 创建任务
        task_main = asyncio.create_task(server_main.serve())
        task_control = asyncio.create_task(server_control.serve())

        # 等待任一任务完成（或取消）
        done, pending = await asyncio.wait(
            [task_main, task_control],
            return_when=asyncio.FIRST_COMPLETED
        )

        # 取消所有任务
        for task in pending:
            task.cancel()

        # 等待所有任务完成
        await asyncio.gather(*pending, return_exceptions=True)


    # 设置信号处理
    loop = asyncio.get_event_loop()


    def signal_handler(sig):
        print(f"接收到信号 {sig.name}，正在关闭服务器...")
        # 关闭服务器
        server_main.should_exit = True
        server_control.should_exit = True
        # 取消所有任务
        for task in asyncio.all_tasks(loop):
            task.cancel()


    # 注册信号处理
    for sig in (signal.SIGINT, signal.SIGTERM):
        loop.add_signal_handler(sig, lambda: signal_handler(sig))

    try:
        loop.run_until_complete(run_servers())
    except asyncio.CancelledError:
        pass
    finally:
        loop.close()
        print("服务器已关闭")